﻿/*
 * =====================================================================================
 *
 *       Filename:  ConfigData.cs
 *
 *    Description:  配置文件实例
 *
 *        Version:  1.0
 *        Created:  
 *       Revision:  none
 *       Compiler:  
 *
 *         Author:   imbedinlove
 *        Company:  
 *       EditTime:  2013年7月16日 15:30:40
 *
 * =====================================================================================

 */

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace ImbedLibrary
{

    /// <summary>
    /// 配置文件操作类
    /// </summary>
    public class ConfigData
    {

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="pathOrName">路径或者文件名字</param>
        public ConfigData(String pathOrName)
        {
            Init(pathOrName);
            GetConfigPath(pathOrName);
        }

        /// <summary>
        /// 文件路径
        /// </summary>
        private String path { get; set; }

        /// <summary>
        /// 配置项保存
        /// </summary>
        private Dictionary<String, String> configData = new Dictionary<String, String>();

        /// <summary>
        /// 配置项行数
        /// </summary>
        private Dictionary<string, int> configLine = new Dictionary<string, int>();

        /// <summary>
        /// 行的原始数据
        /// </summary>
        private Dictionary<int, string> configText = new Dictionary<int, string>();

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="path">文件路径</param>
        private void Init(String path)
        {
            if (path == "" || path == null)
            {
                throw new PathIsNullException();
            }
        }

        /// <summary>
        /// 获取程序运行目录
        /// </summary>
        /// <returns>运行目录</returns>
        private String GetLocalPath()
        {
            return AppDomain.CurrentDomain.BaseDirectory;
        }

        /// <summary>
        /// 获取配置文件路径
        /// </summary>
        /// <param name="path">配置文件路径</param>
        private void GetConfigPath(String path)
        {
            String tempPath = GetLocalPath().Path() + "config\\" + path;
            if (File.Exists(path))
            {
                this.path = path;
            }
            else if (File.Exists(tempPath))
            {
                this.path = tempPath;
            }
            else
            {
                throw new Exception("Error:E01002:配置文件不存在[" + tempPath + "]"); ;
            }
        }

        /// <summary>
        /// 返回FileStream
        /// </summary>
        /// <returns></returns>
        protected  FileStream GetFS(FileMode model,FileAccess access, FileShare share)
        {
            return new FileStream(path, model, access, share);
        }

        /// <summary>
        /// 返回StreamWriter
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        protected StreamWriter GetSW(FileMode mode = FileMode.Append)
        {
            return new StreamWriter(GetFS(mode, FileAccess.Write, FileShare.ReadWrite), Encoding.UTF8);
        }

        /// <summary>
        /// 返回StreamReader
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        protected StreamReader GetSR()
        {
            return new StreamReader(GetFS(FileMode.Open,FileAccess.Read, FileShare.ReadWrite), Encoding.UTF8);
        }

        /// <summary>
        /// GetData
        /// 返回整个Dictionary实例
        /// </summary>
        /// <returns></returns>
        public Dictionary<String, String> GetData()
        {
            if (configData.Count == 0)
            {
                LoadData();
            }
            return configData;
        }

        /// <summary>
        /// GetValue
        /// 返回对应value值
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public String GetValue(String key)
        {
            if (configData.Count == 0) LoadData();
            key = key.ToLower();
            if (configData.ContainsKey(key))
            {
                return configData[key];
            }
            else
            {
                throw new KeyNotFoundException("Error:E01003:不存在key[" + key + "]");
            }
                
        }

        /// <summary>
        /// 加载配置文件
        /// </summary>
        private void LoadData()
        {
            if (configData.Count == 0)
            {
                using (StreamReader sr = GetSR())
                {
                    int line = 0;
                    while (!sr.EndOfStream)
                    {
                        line++;
                        String sLine = sr.ReadLine().Trim();
                        if (sLine == "") continue;
                        if (sLine.IndexOf("#") == 0) continue;
                        String[] data = SplitConfig(sLine);
                        if (data == null) continue;
                        if (data.Length != 2) continue;
                        if (!configData.ContainsKey(data[0].Trim().ToLower()))
                        {
                            configData.Add(data[0].Trim().ToLower(), data[1].Trim());
                            configLine.Add(data[0].Trim().ToLower(), line);
                            configText.Add(line, sLine);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 重新加载配置文件
        /// </summary>
        private void ResLoadData()
        {
            Clear();
            LoadData();
        }

        /// <summary>
        /// 分割配置项 
        /// </summary>
        /// <param name="sLine"></param>
        /// <returns></returns>
        protected String[] SplitConfig(String sLine)
        {
            String[] data = new String[2];
            int charOf = sLine.IndexOf("=");
            if (charOf == -1) { return null; }
            data[0] = sLine.Remove(charOf);
            data[1] = sLine.Replace(data[0]+"=", "");
            return data;
        }

        /// <summary>
        /// 保存配置到配置文件
        /// </summary>
        /// <param name="path">配置文件路径</param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void Set( String key, String value)
        {
            String m = "";
            String k = "";
            using (StreamReader sr = GetSR())
            {
                while (!sr.EndOfStream)
                {
                    String sLine = sr.ReadLine().Trim();

                    if (sLine.Split('=')[0] == key)
                        k = sLine.Split('=')[1];
                    else
                        m += sLine;
                }
            }

            using (StreamWriter sw = GetSW())
            {
                if (k == "")
                    sw.WriteLine(key + "=" + value);
                else
                {
                    String[] t = k.Split('|');
                    if (t.Length == 1)
                    {
                        sw.Write(m = key + "=" + k + "|" + value);
                    }
                    else
                    {
                        for (int i = 0; i < t.Length; i++)
                        {
                            value += "|" + t[i];
                        }
                        m += key + "=" + value;
                        sw.Write(m);
                    }
                }
            }
        }

        /// <summary>
        /// 保存配置
        /// </summary>
        /// <param name="path">配置文件路径</param>
        /// <param name="keyValues">配置集合</param>
        public void Save(Dictionary<string, string> keyValues)
        {
            if (keyValues.Count == 0)
                return;
            foreach (var item in keyValues)
            {
                Save(item.Key.Trim().ToLower(), item.Value, true);
            }
        }

        /// <summary>
        /// 保存配置
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="value">value</param>
        /// <param name="cover">true 覆盖|false 追加</param>
        public void Save( String key, String value,bool cover)
        {
            Save(key, value, cover, false);
        }

        /// <summary>
        /// 保存配置
        /// 默认重复配置追加到配置后面
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="value">value</param>
        public void Save(string key ,string value)
        {
            Save(key, value, false, false);
        }

        /// <summary>
        /// 保存配置文件
        /// 强制重新加载
        /// </summary>
        /// <param name="key">配置项等号左边内容</param>
        /// <param name="value">配置项等号右边内容</param>
        /// <param name="cover">true 覆盖|false 追加</param>
        /// <param name="resLoad">是否重新加载</param>
        public void Save(string key, string value, bool cover, bool resLoad)
        {
            if (resLoad) Clear();
            LoadData();
            key = key.Trim().ToLower();
            if (configData.ContainsKey(key))
            {
                if (cover)
                {
                    Write(configText[configLine[key]], key + " = " + value);
                }
                else
                {
                    Write(configText[configLine[key]], key + " = " + configData[key] + "|" + value);
                }
            }
            else
            {
                Write(key + " = " + value);
            }
            ResLoadData();//重新加载配置文件
        }

        /// <summary>
        /// 更新配置文件
        /// 不存在配置项不报错
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="value">新的value</param>
        public void Update(string key, string value)
        {
            if (configData.Count == 0)
            {
                LoadData();
            }
            if (configData.ContainsKey(key))
            {
                Write(configText[configLine[key]], key + " = " + value);
            }
        }

        /// <summary>
        /// 清空配置文件
        /// </summary>
        private void Clear()
        {
            configData.Clear();
            configLine.Clear();
            configText.Clear();
        }

        /// <summary>
        /// 写入配置
        /// </summary>
        /// <param name="newLine"></param>
        protected void Write(string newLine)
        {
            using (StreamWriter sw = GetSW())
            {
                sw.WriteLine(newLine);
            }
        }

        /// <summary>
        /// 替换配置
        /// </summary>
        /// <param name="oldLine">被替换的行</param>
        /// <param name="newLine">替换的行</param>
        protected void Write( string oldLine,string newLine)
        {
            if (oldLine == newLine)
            {
                return;
            }
            string content = string.Empty;
            using (StreamReader sr = GetSR())
            {
                try
                {
                    content = sr.ReadToEnd();
                }
                catch (Exception)
                {

                    throw;
                }
            }
            content = content.Replace(oldLine, newLine);
            using (StreamWriter sw = GetSW(FileMode.Open))
            {
                sw.Write(content);
            }
        }
    }
}
